package com.castle.fortress.admin.schedule.controler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.date.DateUtil;
import cn.hutool.core.lang.hash.Hash;
import cn.hutool.json.JSONUtil;
import com.castle.fortress.admin.member.dto.MemberDto;
import com.castle.fortress.admin.schedule.model.dto.Attendance;
import com.castle.fortress.admin.schedule.model.dto.UpdateScheduleRequestBody;
import com.castle.fortress.admin.schedule.model.entity.StudySchedule;
import com.castle.fortress.admin.schedule.model.vo.StudyScheduleVO;
import com.castle.fortress.admin.service.StudyScheduleService;
import com.castle.fortress.admin.utils.DateFormatUtil;
import com.castle.fortress.admin.utils.RedisUtils;
import com.castle.fortress.admin.utils.WebUtil;
import com.castle.fortress.common.entity.RespBody;
import com.castle.fortress.common.respcode.GlobalRespCode;
import io.swagger.annotations.Api;
import io.swagger.annotations.ApiOperation;
import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.annotations.Update;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.*;

/**
 * hello demo
 *
 * @author castle
 */
@Api(tags = "AAA可爱学习日程表")
@RestController
@Slf4j
public class StudyScheduleController {
    @Autowired
    StringRedisTemplate stringRedisTemplate;
    @Autowired
    StudyScheduleService studyScheduleService;

    @ApiOperation("获取自己的列表")
    @GetMapping("/schedule/list/me")
    public RespBody listMy() {
        MemberDto member = WebUtil.currentMember();
        List<StudySchedule> schedules = studyScheduleService.listMySchedule(member.getId());

        if (schedules.isEmpty()) {
            RespBody<Object> data = RespBody.data(null);
            data.setMsg("任务完成了，真棒喵~");
            return data;
        }

        // 使用 TreeMap 实现key倒序排序
        Map<String, List<StudyScheduleVO>> res = new TreeMap<>((date1, date2) -> {
            try {
                Date d1 = DateFormatUtil.yyyy_MM_dd.parse(date1);
                Date d2 = DateFormatUtil.yyyy_MM_dd.parse(date2);
                // 倒序排序：d2.compareTo(d1)
                return d2.compareTo(d1);
            } catch (ParseException e) {
                e.printStackTrace();
                log.error("日期解析失败：{}", date1);
                // 如果日期解析失败，按字符串倒序排序作为备选方案
                return date2.compareTo(date1);
            }
        });

        // 先按日期分组
        schedules.forEach(schedule -> res.computeIfAbsent(
                DateFormatUtil.yyyy_MM_dd.format(schedule.getTaskTime()),
                v -> new ArrayList<>()
        ).add(schedule.toVO()));

        return RespBody.data(res);
    }

    @ApiOperation("修改任务状态为完成（只传id）")
    @PostMapping("/schedule/finish")
    public RespBody finishSchedule(@RequestBody UpdateScheduleRequestBody updateScheduleRequestBody) {
        MemberDto member = WebUtil.currentMember();
        StudySchedule byId = studyScheduleService.getById(updateScheduleRequestBody.getId());
        if (byId == null || !byId.getUserId().equals(member.getId())) {
            return RespBody.fail(GlobalRespCode.UNAUTHORIZED);
        }
        Integer status = byId.getStatus();
        byId.setStatus(status == 0 ? 1 : 0);
        if (studyScheduleService.updateById(byId)) {
            doAttendance(member.getId());
            return RespBody.data("修改成功");
        } else {
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    @ApiOperation("修改任务")
    @PostMapping("/schedule/update")
    public RespBody updateSchedule(@RequestBody UpdateScheduleRequestBody requestBody) {
        MemberDto member = WebUtil.currentMember();
        StudySchedule byId = studyScheduleService.getById(requestBody.getId());
        if (byId == null || !byId.getUserId().equals(member.getId())) {
            return RespBody.fail(GlobalRespCode.UNAUTHORIZED);
        }
        // 拷贝
        BeanUtils.copyProperties(requestBody, byId);
        boolean b = studyScheduleService.updateById(byId);
        if (b) {
            doAttendance(member.getId());
            return RespBody.data("修改成功");
        } else {
            return RespBody.fail(GlobalRespCode.OPERATE_ERROR);
        }
    }

    @ApiOperation("获取打卡实体")
    @GetMapping("/attendance")
    public RespBody<Attendance> getAttendance() {
        MemberDto member = WebUtil.currentMember();
        Attendance attendance = getAttendance(member.getId());
        return RespBody.data(attendance);
    }

    private String getRedisKey(Long userId) {
        return "attendance:" + userId;
    }

    private void doAttendance(Long userId) {
        String redisKey = getRedisKey(userId);
        Date now = new Date();

        Attendance attendance = getAttendance(userId);
        // 不存在
        if (attendance == null) {
            Attendance defaultAttendance = new Attendance();
            defaultAttendance.setConsecutiveDays(1);
            defaultAttendance.setTotalDays(1);
            defaultAttendance.setPreviousDate(now);
            // 放个新的，就return
            stringRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(defaultAttendance));
            return;
        }

        // 获取上次打卡日期的开始时间(00:00:00)
        Date previousStartDate = DateUtil.beginOfDay(attendance.getPreviousDate());
        // 获取当前日期的开始时间(00:00:00)
        Date todayStartDate = DateUtil.beginOfDay(now);

        // 计算两个日期开始时间之间的天数差
        long diff = DateUtil.betweenDay(previousStartDate, todayStartDate, true);

        if (diff == 1) {
            // 昨天和今天相差一天，连续打卡
            attendance.setConsecutiveDays(attendance.getConsecutiveDays() + 1);
            attendance.setTotalDays(attendance.getTotalDays() + 1);
        } else if (diff > 1) {
            // 间隔超过一天，重新计算连续天数
            attendance.setTotalDays(attendance.getTotalDays() + 1);
            attendance.setConsecutiveDays(1);
        }

        // diff == 0 表示同一天内多次打卡，不增加天数也不重置连续天数
        // diff < 0 代表补签，不增加天数也不重置连续天数

        attendance.setPreviousDate(now);
        stringRedisTemplate.opsForValue().set(redisKey, JSONUtil.toJsonStr(attendance));
    }


    private Attendance getAttendance(Long userId) {
        String redisKey = getRedisKey(userId);
        if (stringRedisTemplate.hasKey(redisKey) == false) {
            return null;
        }
        String jsonStr = stringRedisTemplate.opsForValue().get(redisKey);
        return JSONUtil.toBean(jsonStr, Attendance.class);
    }
}